package com.wx.pojo;

import cn.hutool.core.util.ReUtil;
import com.wx.temp.Inner;
import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @author wangxun NotAuthUrlProperties
 * 配置在白名单中的路径不会进行 token 的校验
 * 在 Nacos 中修改配置之后，不仅会将修改后的配置设置到对应的成员变量中，而且还会执行对应的 InitializingBean 的 afterPropertiesSet() 方法
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "while.path")
public class GatewayWhilePath implements InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;
    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");

    /**
     * 正常的路径，如：/student-web/student/getStudent
     */
    private Set<String> normalUrls;

    /**
     * PathVariable 路径，如：/student-web/student/getStudent/{id}  -->  /student-web/student/getStudent/1001
     */
    private List<String> variableUrls;

    @Override
    public void afterPropertiesSet() throws Exception {
        RequestMappingHandlerMapping mapping = this.applicationContext.getBean(RequestMappingHandlerMapping.class);
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
        map.keySet().forEach((info) -> {
            HandlerMethod handlerMethod = map.get(info);
            Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
            Optional.ofNullable(method).ifPresent((inner) -> {
                info.getPatternsCondition().getPatterns().forEach((url) -> {
                    // "/a/b/{a}/{b}" --> "/a/b/*/*"
                    this.variableUrls.add(ReUtil.replaceAll(url, PATTERN, "*"));
                });
            });
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
